//头文件，全局变量函数定义区域
#include<stdio.h>
#include<string.h>
#define MAX 1024

//程序1
//利用指针模拟实现strcmp函数
void test1()
{
	char str1[MAX];
	char* targets1 = str1;
	printf("请输入第一段比较字符串：");
	fgets(str1, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
			break;
		}
	}

	char str2[MAX];
	char* targets2 = str2;
	printf("请输入第二段字符串：");
	fgets(str2, MAX, stdin);
	for(int i = 0;i<MAX;i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
			break;
		}
	}

	printf("------开始比较-------\n");
	int n = 1;//初始化计数器，并分析是在哪个字符处不相等

	//循环条件为*targets1与*targets2两个指针所指向的值是不是到末尾了
	while (*targets1 != '\0' && *targets2 != '\0')
		//你可能忘记了这个部分，所以我就单独给领出来给你复习了
	/*
	运算符		含义			优先级		举例				说明
	  ！			逻辑非		高			！a				如果a为真，!a为假
														如果a为假，！a为真

	  &&		逻辑与		中			a&&b			只有a和b同时为真，结果才为真。
														只要a和b其中有一个为假，结果为假。（同真为真，一假为假）

	  ||		逻辑或		低			a||b			只要a和b其中一个为真，结果为真；
														只有a和b同时为假，结果为假；（一真为真，全假为为假）
	*/
	{
		if (*targets1++ != *targets2++) //这里是两重含义,先运行*targets1++和*targets2++,然后再进行*targets1 != *targets2;
		{								//要是这么写也没问题：
			break;						//		while(*targets1 !=  '\0' && *targets2 != '\0')
		}								//		{
		n++;							//			*targets1++;
										//			*targets2++;
										//			if(*targets1 != *targets2)
										//			{
										//				break;
										//			}
										//			n++;
	}									//		}
	

	if (*targets1 == '\0' && *targets2 == '\0')
	{
		printf("两个字符串输入相等");
	}
	else
	{
		printf("两个字符串不相等,第%d个字符出现不同!\n", n);
	}

}

//程序2
//利用strcmp判断用户输入的字符串是否相等
void test2()
{
	char str1[MAX];
	printf("请输入第一段字符串：");
	fgets(str1, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
		}

	}



	char str2[MAX];
	printf("请输入第二段字符串：");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
		}
	}

	printf("---开始比较----\n");
	 
	/*
	strcmp函数

	函数概要：
		strcmp 函数用于比较两个字符串。
		该函数从第一个字符开始，依次比较每个字符的 ASCII 码大小，直到发现两个字符不相等或抵达结束符（'\0'）为止。

	函数原型：
		#include <string.h>
		...
		int strcmp(const char *s1, const char *s2);

	参数解析：
		参数				含义
		s1				指向待比较的字符串1
		s2				指向待比较的字符串2

	返回值：
		返回一个整数表示两个字符串的大小关系

		返回值			含义
		< 0				字符串 1 的字符小于字符串 2 对应位置的字符
		0				两个字符串的内容完全一致
		> 0				字符串 1 的字符大于字符串 2 对应位置的字符

	注：
		若要使用strcmp函数，必须使用if函数进行搭配，因为得出的结果是一个真假（bool类型）
		
	*/


	int result = strcmp(str1, str2);
	if (result == 0)
	{
		printf("两个输入字符串一样");
	}
	else//利用数组+循环查找不一样的地方
	{	
		int n = 0;
		for (int i = 0; str1[i] != '\0' && str2[2] != '\0'; i++)//是不是似曾相识？哎，对了就是程序1上面的代码：while (*targets1 != '\0' && *targets2 != '\0')，这就是数组和指针的关系，两个玩意就是双胞胎。有相同的点，那就是他们都是指向一个地址
																//不难看出用指针去模拟strcmp函数更加省代码
		{
			if (str1[i] != str2[i])
			{
				n = i + 1;
				break;
			}

		}
		printf("两个字符串不相等，第%d字符串出现不同！\n", n);
	}

}
//程序3
//利用strncmp函数对用户选定的字符串进行比较

void test3()
{
	char str1[MAX];
	printf("请输入第一个字符串：");
	fgets(str1, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
			break;
		}
	}

	char str2[MAX];
	printf("请输入第二个字符串：");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
			break;
		}
	}

	printf("请输入要比较的字符串个数：");
	int n;
	scanf("%d", &n);

	/*
		strncmp函数

	函数概要：
		strncmp 函数用于比较两个字符串的前 n 个字符。
		该函数从第一个字符开始，依次比较每个字符的 ASCII 码大小，发现两个字符不相等或抵达结束符（'\0'）为止，或者前 n 个字符完全一样，也会停止比较。

	函数原型：
		#include <string.h>
		...
		int strncmp(const char *s1, const char *s2, size_t n);
		
	参数解析：
		参数						含义
		s1						指向待比较的字符串 1
		s2						指向待比较的字符串 2
		n						指定待比较的字符数

	返回值：
		返回一个整数表示两个字符串的关系。
		返回值						含义
		 < 0						字符串 1 的字符小于字符串 2 对应位置的字符
		   0						两个字符串的内容完全一致
		 > 0						字符串 1 的字符大于字符串 2 对应位置的字符
	
	*/


	int result = strncmp(str1, str2, n);
	if (!result)
	{
		printf("str1和str2前%d个字符相同！\n", n);
	}
	else
	{
		int a;
		for (int i = 0; str1[i] == '\0' && str2[i] == '\0';i++)
		{
			if (str1[i] != str2[i])
			{
				a = i + 1;
				break;
			}
			
		}
		printf("两个字符串不相同，第%d个字符出现不同", a);
	}


}

//程序4
//使用指针模拟strncmp对用户选定的字符进行比较（中英文混写）

void test4()
{
	char str1[MAX];
	char* targets1 = str1;
	printf("请输入第一个字符串：");
	fgets(str1, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str1[i] == '\n')
		{
			str1[i] = '\0';
			break;
		}
	}

	char str2[MAX];
	char* targets2 = str2;
	printf("请输入第二段字符串：");
	fgets(str2, MAX, stdin);
	for (int i = 0; i < MAX; i++)
	{
		if (str2[i] == '\n')
		{
			str2[i] = '\0';
			break;
		}
	}

	int n;
	printf("请输入要比较的字符串数：");
	scanf("%d", &n);

	int index = 1;//初始化计数器
	char ch;
	while (n && *targets1 != '\0' && *targets2 != '\0')//只要比较的字符串数n不为0，并且两个字符串没到结束标识，继续循环。(比如说n设置比两个字符串数多)
	/*
		特别注意的是：这里也遵循短路求值关系
		短路求值：短路求值又称最小化求值，是一种逻辑运算符的求值策略。只有当第一个运算数的值无法确定逻辑运算的结果时，才对第二个运算数进行求值。C 语言对于逻辑与和逻辑或采用短路求值的方式。

		* 在C语言中， while(n && *targets1!= '\0' && *targets2!= '\0') 遵循短路求值。
		短路求值的规则是：对于逻辑与（ && ）操作，如果第一个操作数为假（ 0 ），则整个表达式的值必定为假，此时不会再去计算第二个及后续的操作数；只有当第一个操作数为真时，才会继续计算第二个操作数，以此类推。
		在这个 while 循环条件中：
		- 如果 n 为 0 （假），那么由于逻辑与的短路特性， *targets1!= '\0' 和 *targets2!= '\0' 这两个条件就不会再被计算，直接判定整个循环条件为假，循环结束。
		- 只有当 n 不为 0 （真）时，才会继续判断 *targets1!= '\0' ，如果 *targets1 等于 '\0' （假），那么同样由于短路特性， *targets2!= '\0' 也不会再被计算，循环条件为假，循环结束；只有当 n 不为 0 且 *targets1!= '\0' 为真时，才会去判断 *targets2!= '\0' 。
		这种短路求值机制在很多情况下可以提高程序的效率，避免不必要的计算，例如当 n 已经为 0 时，就无需再去检查字符串是否结束等条件。同时，也可以在某些情况下避免因后续条件计算可能出现的错误（例如指针未初始化等情况），因为如果前面的条件已经能确定整个表达式的结果，后续条件就不会被执行。
	*/
	
	
	{
		ch = *targets1;
		//中文符号检测循环代码
		if ((int)ch < 0)
		{
			if (*targets1++ != *targets2++)
			{
				break;
			} 

		}
		//非中文符号检测循环代码
		if (*targets1++ != *targets2++)
		{
			break;
		}

		index++;
		n--;
	}

	
	if ((n == 0) || (*targets1 == '\0' && *targets2 == '\0'))
	{
		printf("两个字符串的前%d个字符完全相同!\n", index);
	}
	else
	{
		printf("两个字符串不完全相同,第%d个字符出现不同！\n", index);
	}
}

//主函数
int main()
{
	/*
		索引				含义
		test1			利用指针模拟实现strcmp函数
		test2			利用strcmp判断用户输入的字符串是否相等
		test3			利用strncmp函数对用户选定的字符串进行比较
		test4			使用指针模拟strncmp对用户选定的字符进行比较（中英文混写）

	*/
	test4();
	return 0;
}